import { Injectable } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { TimeUnitType } from "st-common-core";
import { isEmpty, objConvert } from "st-common-core";
import { has, set } from "../common/redis";
import { RedisKeyConst } from "../common/redis";
import { EnvNameEnum } from "../common/env";
import { UserService, UserVo, userVoDefault, verifyUserPassword, UserEntityPropNameEnum } from "../user";

/**
 * 登录服务
 */
@Injectable()
export class LoginService {

  constructor(
    private readonly configService: ConfigService,
    private readonly userService: UserService
  ) {
  }

  /**
   * 通过密码登录
   *
   * @param {string} username 用户名或账号
   * @param {string} password 密码
   * @returns {Promise<UserVo | null>} 登录成功，返回相应的用户信息 VO 对象，否则返回 null
   */
  async loginByPwd(username: string, password: string): Promise<UserVo | null> {
    // 校验用户名或账号和密码是否为空
    if (isEmpty(username) || isEmpty(password)) return null;
    // 根据用户名或账号查询用户
    const user = await this.userService.findByUsernameOrAccount(username);
    // 查询的用户不存在
    if (!user) return null;
    // 校验密码
    const isPwdCorrect = verifyUserPassword(
      password,
      user[UserEntityPropNameEnum.SALT],
      user[UserEntityPropNameEnum.PASSWORD]
    );
    // 密码校验不通过
    if (!isPwdCorrect) return null;
    // 根据用户信息对象生成用户信息 VO 对象
    const userVo = objConvert<UserVo>(user, { ...userVoDefault });
    // 缓存登录成功的用户信息 VO 对象到 Redis 中
    const isCacheSuccess = await set({
      key: RedisKeyConst.USER_LOGIN_CREDENTIAL() + user[UserEntityPropNameEnum.ID],
      value: userVo,
      expire: this.configService.get<number>(EnvNameEnum.REDIS_USER_EXPIRE),
      unit: this.configService.get<TimeUnitType>(EnvNameEnum.REDIS_USER_EXPIRE_UNIT)
    })
    // 缓存失败
    if (!isCacheSuccess) return null;
    // 登录成功，返回用户信息 VO 对象
    return userVo;
  }

  /**
   * 判断用户登录是否有效，根据 Redis 中缓存的登录用户信息 VO 对象判断，如果 Redis 中存在
   * 缓存，则认为用户登录有效，否则认为用户登录无效
   *
   * @param {number} loginCredential 用户登录凭证
   * @returns {Promise<boolean>} 是否登录有效，true 为有效，false 为无效
   */
  async judgeLoginEffective(loginCredential: number) {
    return await has(RedisKeyConst.USER_LOGIN_CREDENTIAL() + loginCredential)
  }

}
